home *** CD-ROM | disk | FTP | other *** search
- /*
- * CALC.C
- *
- * Author: R. E. Sawyer
- *
- * Date: 16 Nov 85
- *
- * Language: C (DeSmet V2.4)
- *
- * Description: CALC is an interactive RPN-style calculator. Each line of
- * instructions entered at the keyboard is immediately interp-
- * reted, and CALC may also be directed to save each line in a
- * journal file for later re-play. Such a file may also be
- * created by previous use of a text editor.
- */
-
- #include <math.h>
- #include <stdio.h>
-
- #define MAXLINE 80
- #define MAXWORD 20
- #define MAXSTACK 100
- #define MAXMEM 100
- #define MAXKEY 100
- #define MAXVAR 100
- #define MAXVLEN 6
- #define TAB " "
-
- FILE *fin = 0;
- FILE *fout = 0;
- int isfromfile = 0;
- int istofile = 0;
-
- static char vname[MAXVAR][MAXVLEN] = {"\0"};
- static double val[MAXVAR] = {0.0};
- int vnum = 0;
-
- int sp = 0;
- double stack[MAXSTACK+1];
- double mem[MAXMEM+1];
- extern double atof();
-
- static char *keyword[] = {
- "HELP display this summary",
- "QUIT exit CALC",
- "nnn append s0 = any number nnn",
- "abc append s0 = value of variable abc",
- "=abc store s0 as variable abc, delete s0",
- "= display s0",
- "+ s0 <-- s1 + s0, delete s1",
- "- s0 <-- s1 - s0, delete s1",
- "* s0 <-- s1 * s0, delete s1",
- "/ s0 <-- s1 / s0, delete s1",
- "^ s0 <-- s1 to the power s0, delete s1",
- "?< s0 <-- 1(0) if s1 < (>=) s0, delete s1",
- "?<= s0 <-- 1(0) if s1 <= (>) s0, delete s1",
- "?= s0 <-- 1(0) if s1 = (<>) s0, delete s1",
- "ABS s0 <-- absolute value of s0",
- "ACOS s0 <-- arccosine of s0",
- "ASIN s0 <-- arcsine of s0",
- "ATAN s0 <-- arctangent of s0",
- "CEIL s0 <-- least integer not less than s0",
- "CHS s0 <-- -s0",
- "COS s0 <-- cosine of s0",
- "COSH s0 <-- hyperbolic cosine of s0",
- "EXP s0 <-- e to the power s0",
- "EXP10 s0 <-- 10 to the power s0",
- "FLOOR s0 <-- greatest integer not greater than s0",
- "INV s0 <-- 1 / s0",
- "LOG s0 <-- base e logarithm of s0",
- "LOG10 s0 <-- base 10 logarithm of s0",
- "MAX s0 <-- maximum of s0 & s1, delete s1",
- "MIN s0 <-- minimum of s0 & s1, delete s1",
- "MOD s0 <-- s1 modulo s0, delete s1",
- "PSE pause until any key is typed (and ignored)",
- "PI append s0 = 3.14159...",
- "SIN s0 <-- sine of s0",
- "SINH s0 <-- hyperbolic sine of s0",
- "SQR s0 <-- s0 * s0",
- "SQRT s0 <-- square root of s0",
- "TAN s0 <-- tangent of s0",
- "TANH s0 <-- hyperbolic tangent of s0",
- "CL0 delete s0",
- "CLA delete stack & variables, zero all registers",
- "CLM zero all registers",
- "CLS delete stack",
- "CLV delete all variables",
- "RCL append s0 = register s0",
- "SHO display stack",
- "XCH exchange s0,s1",
- "STO store s1 in register s0, delete s0",
- "STO+ add s1 to register s0, delete s0",
- "STO- subtract s1 from register s0, delete s0",
- "STO* multiply register s0 by s1, delete s0",
- "STO/ divide register s0 by s1, delete s0",
- "<<abc execute instructions in file abc",
- ">>abc begin saving instructions to file abc",
- ">> stop saving instructions to file"
- };
-
- main()
- {
- int i, j;
- char line[MAXLINE+1];
- char word[MAXWORD+1];
- int start;
- int iop1;
- double op1, op2;
- double push(), pop();
- FILE *opener();
-
- header();
- while (TRUE)
- {
- start = 0;
- if (!isfromfile)
- printf("CALC> ");
- getline(line);
- if (istofile && !(line[0] == '>' && line[1] == '>'))
- {
- fputs(line,fout);
- fputs("\n",fout);
- }
- if (isfromfile)
- printf("%s",line);
- while (getword(word, line, &start))
- {
- if (word[0] == '<' && word[1] == '<')
- {
- fin = opener(word+2,0);
- isfromfile = fin;
- break;
- }
- if (word[0] == '>' && word[1] == '>')
- {
- if (istofile)
- {
- fclose(fout);
- istofile = 0;
- }
- else if (!isfromfile)
- {
- fout = opener(word+2,1);
- istofile = fout;
- break;
- }
- }
- else if (word[0] == '=' && isalpha(word[1]))
- if (sp > 0)
- if ( (i=search(vname,word+1)) >= 0 )
- val[i] = pop();
- else
- if (vnum <= MAXVAR)
- {
- strcpy(vname+vnum, word+1);
- val[vnum] = pop();
- ++vnum;
- }
- else
- printf("%sNo room for %s.\n",TAB,word+1);
- else
- printf("%sNothing to store in %s.\n",TAB,word+1);
- else if (isdigit(word[0]) || word[0] == '.')
- push(atof(word));
- else if (word[0] == '-' && (isdigit(word[1]) || word[1] == '.'))
- push(-atof(word+1));
- else if (is(word,"CL0"))
- if (sp > 0)
- pop();
- else
- printf("%sNothing to clear.\n",TAB);
- else if (is(word,"STO"))
- if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
- mem[iop1] = push(pop());
- else
- {
- printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
- break;
- }
- else if (is(word,"STO+"))
- if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
- mem[iop1] += push(pop());
- else
- {
- printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
- break;
- }
- else if (is(word,"STO-"))
- if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
- mem[iop1] -= push(pop());
- else
- {
- printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
- break;
- }
- else if (is(word,"STO*"))
- if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
- mem[iop1] *= push(pop());
- else
- {
- printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
- break;
- }
- else if (is(word,"STO/"))
- if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
- mem[iop1] /= push(pop());
- else
- {
- printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
- break;
- }
- else if (is(word,"RCL"))
- if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
- push(mem[iop1]);
- else
- {
- printf("%sMust have 0<=M<=%3.0d in M RCL.\n",TAB,MAXMEM);
- break;
- }
- else if (is(word,"+"))
- push(pop() + pop());
- else if (is(word,"*"))
- push(pop() * pop());
- else if (is(word,"-"))
- {
- op2 = pop();
- push(pop() - op2);
- }
- else if (is(word,"/"))
- {
- op2 = pop();
- if (op2 != 0.0)
- push(pop() / op2);
- else
- {
- printf("%sAttempted division by zero.\n",TAB);
- break;
- }
- }
- else if (is(word,"?<"))
- {
- op2 = pop();
- push(pop() < op2 ? 1.0 : 0.0);
- }
- else if (is(word,"?<="))
- {
- op2 = pop();
- push(pop() <= op2 ? 1.0 : 0.0);
- }
- else if (is(word,"?="))
- {
- op2 = pop();
- push(pop() == op2 ? 1.0 : 0.0);
- }
- else if (is(word,"CHS"))
- push(-pop());
- else if (is(word,"XCH"))
- {
- op1 = pop();
- op2 = pop();
- push(op1);
- push(op2);
- }
- else if (is(word,"INV"))
- if ((op1=pop()) != 0.0)
- push(1.0 / pop());
- else
- {
- printf("%sMust have X<>0 in 1/X.\n",TAB);
- break;
- }
- else if (is(word,"ABS"))
- push(fabs(pop()));
- else if (is(word,"ACOS"))
- push(acos(pop()));
- else if (is(word,"ASIN"))
- push(asin(pop()));
- else if (is(word,"ATAN"))
- push(atan(pop()));
- else if (is(word,"CEIL"))
- push(ceil(pop()));
- else if (is(word,"COS"))
- push(cos(pop()));
- else if (is(word,"EXP"))
- push(exp(pop()));
- else if (is(word,"EXP10"))
- push(exp10(pop()));
- else if (is(word,"FLOOR"))
- push(floor(pop()));
- else if (is(word,"LOG"))
- if ((op1=pop()) > 0.0)
- push(log(op1));
- else
- {
- printf("%sMust have X>0 in LOG(X).\n",TAB);
- break;
- }
- else if (is(word,"LOG10"))
- if ((op1=pop()) > 0.0)
- push(log10(op1));
- else
- {
- printf("%sMust have X>0 LOG10(X).\n",TAB);
- break;
- }
- else if (is(word,"^"))
- if ((op2 = pop()) > 0.0)
- push(pow(pop(), op2));
- else
- {
- printf("%sMust have X>0 in X^Y.\n", TAB);
- break;
- }
- else if (is(word,"SIN"))
- push(sin(pop()));
- else if (is(word,"SQR"))
- push((op1=pop()) * op1);
- else if (is(word,"SQRT"))
- if ((op1=pop()) >= 0.0)
- push(sqrt(op1));
- else
- {
- printf("%sMust have X>=0 in SQRT(X).\n",TAB);
- break;
- }
- else if (is(word,"TAN"))
- push(tan(pop()));
- else if (is(word,"MIN"))
- {
- op2 = pop();
- push(((op1 = pop()) < op2) ? op1 : op2);
- }
- else if (is(word,"MAX"))
- {
- op2 = pop();
- push(((op1 = pop()) > op2) ? op1 : op2);
- }
- else if (is(word,"SINH"))
- push(0.5*(exp(op1=pop()) - exp(-op1)));
- else if (is(word,"COSH"))
- push(0.5*(exp(op1=pop()) + exp(-op1)));
- else if (is(word,"TANH"))
- {
- op2 = exp(op1=pop()) - exp(-op1);
- push(op2 / (exp(op1) + exp(-op1)));
- }
- else if (is(word,"PI"))
- push(4.0*atan(1.0));
- else if (is(word,"="))
- if (sp > 0)
- printf("%s%20.14le\n", TAB, push(pop()));
- else
- printf("%sStack empty.\n",TAB);
- else if (is(word,"CLS"))
- clearstack();
- else if (is(word,"CLM"))
- clearmem();
- else if (is(word,"CLV"))
- clearvar();
- else if (is(word,"CLA"))
- {
- clearstack();
- clearmem();
- clearvar();
- }
- else if (is(word,"SHO"))
- showstack();
- else if (is(word,"HELP"))
- help();
- else if (is(word,"QUIT"))
- exit();
- else if ( (i=search(vname,word)) >= 0 )
- push(val[i]);
- else if (is(word,"PSE"))
- {
- getchar();
- putchar('\b\n');
- }
- else
- {
- printf("%sUnrecognized symbol: %s\n", TAB, word);
- printf("%sDo you want help? (y/n) ",TAB);
- if (tolower(getchar()) == 'y')
- help();
- else
- printf("\n");
- }
- }
- }
- }
-
-
- double push(x)
- double x;
- {
- if (sp < MAXSTACK)
- {
- stack[sp++] = x;
- }
- else
- {
- printf("%sStack overflow.\n", TAB);
- clearstack();
- }
- return (x);
- }
-
-
- double pop()
- {
- double x;
-
- if (sp > 0)
- x = stack[--sp];
- else
- {
- printf("%sValue not found -- stack may be corrupted.\n", TAB);
- clearstack();
- x = 0.0;
- }
- return (x);
- }
-
-
- void clearstack()
- {
- sp = 0;
- }
-
-
- void showstack()
- {
- int i;
- if (sp == 0)
- {
- printf("%sStack empty.\n", TAB);
- return;
- }
- for (i=0; i<sp-1; ++i)
- printf("%s%20.14le\n", TAB, stack[i]);
- printf("%s%20.14le <--TOP\n", TAB, stack[sp-1]);
- }
-
-
- void clearmem()
- {
- int i;
-
- for (i=0; i<=MAXMEM; ++i)
- mem[i] = 0;
- }
-
-
- void clearvar()
- {
- vnum = 0;
- vname[0][0] = '\0';
- }
-
-
- void help()
- {
- int i;
-
- printf("\n\n\n\n\n\n");
- printf("%sCALC is an interactive RPN-style calculator with an \n",TAB);
- printf("%sinstruction set resembling that of an HP calculator.\n",TAB);
- printf("%sEach line of instructions entered at the keyboard is\n",TAB);
- printf("%simmediately executed, and may also be automatically \n",TAB);
- printf("%sjournaled in a command file. CALC can be made to read\n",TAB);
- printf("%sand execute the instructions on-file at any time. A\n",TAB);
- printf("%scommand file can also be created with a text editor.\n",TAB);
- printf("\n%sAs in an HP calulator, instructions are interpreted\n",TAB);
- printf("%sas \"Reverse Polish Notation\", and operate on values\n",TAB);
- printf("%sstored on a \"stack\" -- a \"last-in first-out\" list.\n",TAB);
- printf("%sThe stack is represented as (...,s2,s1,s0), where s0\n",TAB);
- printf("%sis accessed first (\"top-of-stack\"), s1 is next, etc.\n",TAB);
- printf("%sAll values are double precision (8-byte) floats.\n\n",TAB);
- printf("%sThe following are valid symbols if separated by spaces:\n",TAB);
- printf("\n\n\n\n\n\n");
- more();
- for (i=0; i<MAXKEY && *keyword[i] != '\0'; ++i)
- {
- if (i%24 == 0 && i>0)
- more();
- printf("%s%s\n",TAB,keyword[i]);
- }
- printf("\n\n");
- }
-
- more()
- {
- printf("-MORE-");
- getchar();
- printf("\b\b\b\b\b\b\b");
- }
-
- static char *q[3] = {"r","w","a"};
-
- FILE *opener(s,t)
- char *s;
- int t;
- {
- FILE *f;
-
- if ((f = fopen(s,q[t])) == NULL)
- printf("%sCan't open %s.\n",TAB,s);
- return (f);
- }
-
-
- /* get a line of text, from the keyboard or a file, to line[] string*/
- int getline(line)
- char line[];
- {
- if (isfromfile)
- {
- if (fgets(line,MAXLINE,fin) == NULL)
- {
- fclose(fin);
- isfromfile = 0;
- }
- }
- else
- gets(line);
- }
-
- /* get word-string from line-string beginning at index=start */
- /* return length of word-string */
-
- int getword(word, line, start)
- char word[];
- char line[];
- int *start;
- {
- int i, j;
-
- for (i=*start, j=0; line[i] != '\0'; ++i)
- {
- if (!isop(line[i]))
- ;
- else
- {
- for (j=0; j <= MAXWORD && isop(line[i]); ++j)
- word[j] = toupper(line[i++]);
- word[j] = '\0';
- *start = i;
- break;
- }
- }
- if (j == 0)
- word[0] = '\0';
- if (j > MAXWORD)
- {
- printf("%sSymbol too long: %s", TAB, word);
- for (i=*start; i<=MAXLINE && isop(line[i]); ++i)
- printf("%c", toupper(line[i]));
- printf("\n");
- }
- return (j);
- }
-
-
- /* return TRUE if c is in the alphabet for words */
-
- int isop(c)
- char c;
- {
- int i;
-
- if (c >= '!' && c <= '~')
- return (TRUE);
- else
- return (FALSE);
- }
-
-
- int is(word, str)
- char word[];
- char str[];
- {
- return (strcmp(word, str) == 0);
- }
-
-
- int search(var, word)
- char var[][MAXVLEN];
- char word[];
- {
- int i;
-
- for (i=0; i <= MAXVAR && (var[i][0] != '\0'); ++i)
- if (is(word,var[i]))
- return (i);
- return (-1);
- }
-
- void header()
- {
- printf("\nCALC -- R. E. Sawyer, 16 Nov 85\n\n");
- }
-